home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / io / BufferedReader.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  13.0 KB  |  449 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)BufferedReader.java    1.19 98/08/18
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17.  
  18. /**
  19.  * Read text from a character-input stream, buffering characters so as to
  20.  * provide for the efficient reading of characters, arrays, and lines.
  21.  *
  22.  * <p> The buffer size may be specified, or the default size may be used.  The
  23.  * default is large enough for most purposes.
  24.  *
  25.  * <p> In general, each read request made of a Reader causes a corresponding
  26.  * read request to be made of the underlying character or byte stream.  It is
  27.  * therefore advisable to wrap a BufferedReader around any Reader whose read()
  28.  * operations may be costly, such as FileReaders and InputStreamReaders.  For
  29.  * example,
  30.  *
  31.  * <pre>
  32.  * BufferedReader in
  33.  *   = new BufferedReader(new FileReader("foo.in"));
  34.  * </pre>
  35.  *
  36.  * will buffer the input from the specified file.  Without buffering, each
  37.  * invocation of read() or readLine() could cause bytes to be read from the
  38.  * file, converted into characters, and then returned, which can be very
  39.  * inefficient. 
  40.  *
  41.  * <p> Programs that use DataInputStreams for textual input can be localized by
  42.  * replacing each DataInputStream with an appropriate BufferedReader.
  43.  *
  44.  * @see FileReader
  45.  * @see InputStreamReader
  46.  *
  47.  * @version     1.19, 98/08/18
  48.  * @author    Mark Reinhold
  49.  * @since    JDK1.1
  50.  */
  51.  
  52. public class BufferedReader extends Reader {
  53.  
  54.     private Reader in;
  55.  
  56.     private char cb[];
  57.     private int nChars, nextChar;
  58.  
  59.     private static final int INVALIDATED = -2;
  60.     private static final int UNMARKED = -1;
  61.     private int markedChar = UNMARKED;
  62.     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
  63.  
  64.     private static int defaultCharBufferSize = 8192;
  65.     private static int defaultExpectedLineLength = 80;
  66.  
  67.     /**
  68.      * Create a buffering character-input stream that uses an input buffer of
  69.      * the specified size.
  70.      *
  71.      * @param  in   A Reader
  72.      * @param  sz   Input-buffer size
  73.      *
  74.      * @exception  IllegalArgumentException  If sz is <= 0
  75.      */
  76.     public BufferedReader(Reader in, int sz) {
  77.     super(in);
  78.     if (sz <= 0)
  79.         throw new IllegalArgumentException("Buffer size <= 0");
  80.     this.in = in;
  81.     cb = new char[sz];
  82.     nextChar = nChars = 0;
  83.     }
  84.  
  85.     /**
  86.      * Create a buffering character-input stream that uses a default-sized
  87.      * input buffer.
  88.      *
  89.      * @param  in   A Reader
  90.      */
  91.     public BufferedReader(Reader in) {
  92.     this(in, defaultCharBufferSize);
  93.     }
  94.  
  95.     /** Check to make sure that the stream has not been closed */
  96.     private void ensureOpen() throws IOException {
  97.     if (in == null)
  98.         throw new IOException("Stream closed");
  99.     }
  100.  
  101.     /**
  102.      * Fill the input buffer, taking the mark into account if it is valid.
  103.      */
  104.     private void fill() throws IOException {
  105.     int dst;
  106.     if (markedChar <= UNMARKED) {
  107.         /* No mark */
  108.         dst = 0;
  109.     } else {
  110.         /* Marked */
  111.         int delta = nextChar - markedChar;
  112.         if (delta >= readAheadLimit) {
  113.         /* Gone past read-ahead limit: Invalidate mark */
  114.         markedChar = INVALIDATED;
  115.         readAheadLimit = 0;
  116.         dst = 0;
  117.         } else {
  118.         if (readAheadLimit <= cb.length) {
  119.             /* Shuffle in the current buffer */
  120.             System.arraycopy(cb, markedChar, cb, 0, delta);
  121.             markedChar = 0;
  122.             dst = delta;
  123.         } else {
  124.             /* Reallocate buffer to accomodate read-ahead limit */
  125.             char ncb[] = new char[readAheadLimit];
  126.             System.arraycopy(cb, markedChar, ncb, 0, delta);
  127.             cb = ncb;
  128.             markedChar = 0;
  129.             dst = delta;
  130.         }
  131.                 nextChar = nChars = delta;
  132.         }
  133.     }
  134.  
  135.     int n;
  136.     do {
  137.         n = in.read(cb, dst, cb.length - dst);
  138.     } while (n == 0);
  139.     if (n > 0) {
  140.         nChars = dst + n;
  141.         nextChar = dst;
  142.     }
  143.     }
  144.  
  145.     /**
  146.      * Read a single character.
  147.      *
  148.      * @exception  IOException  If an I/O error occurs
  149.      */
  150.     public int read() throws IOException {
  151.     synchronized (lock) {
  152.         ensureOpen();
  153.         if (nextChar >= nChars) {
  154.         fill();
  155.         if (nextChar >= nChars)
  156.             return -1;
  157.         }
  158.         return cb[nextChar++];
  159.     }
  160.     }
  161.  
  162.     /**
  163.      * Read characters into a portion of an array, reading from the underlying
  164.      * stream at most once if necessary.
  165.      */
  166.     private int read1(char[] cbuf, int off, int len) throws IOException {
  167.     if (nextChar >= nChars) {
  168.         /* If the requested length is at least as large as the buffer, and
  169.            if there is no mark/reset activity, do not bother to copy the
  170.            characters into the local buffer.  In this way buffered streams
  171.            will cascade harmlessly. */
  172.         if (len >= cb.length && markedChar <= UNMARKED) {
  173.         return in.read(cbuf, off, len);
  174.         }
  175.         fill();
  176.     }
  177.     if (nextChar >= nChars) return -1;
  178.     int n = Math.min(len, nChars - nextChar);
  179.     System.arraycopy(cb, nextChar, cbuf, off, n);
  180.     nextChar += n;
  181.     return n;
  182.     }
  183.  
  184.     /**
  185.      * Read characters into a portion of an array.
  186.      *
  187.      * <p> This method implements the general contract of the corresponding
  188.      * <code>{@link Reader#read(char[], int, int) read}</code> method of the
  189.      * <code>{@link Reader}</code> class.  As an additional convenience, it
  190.      * attempts to read as many characters as possible by repeatedly invoking
  191.      * the <code>read</code> method of the underlying stream.  This iterated
  192.      * <code>read</code> continues until one of the following conditions becomes
  193.      * true: <ul>
  194.      *
  195.      *   <li> The specified number of characters have been read,
  196.      *
  197.      *   <li> The <code>read</code> method of the underlying stream returns
  198.      *   <code>-1</code>, indicating end-of-file, or
  199.      *
  200.      *   <li> The <code>ready</code> method of the underlying stream
  201.      *   returns <code>false</code>, indicating that further input requests
  202.      *   would block.
  203.      *
  204.      * </ul> If the first <code>read</code> on the underlying stream returns
  205.      * <code>-1</code> to indicate end-of-file then this method returns
  206.      * <code>-1</code>.  Otherwise this method returns the number of characters
  207.      * actually read.
  208.      *
  209.      * <p> Subclasses of this class are encouraged, but not required, to
  210.      * attempt to read as many characters as possible in the same fashion.
  211.      *
  212.      * <p> Ordinarily this method takes characters from this stream's character
  213.      * buffer, filling it from the underlying stream as necessary.  If,
  214.      * however, the buffer is empty, the mark is not valid, and the requested
  215.      * length is at least as large as the buffer, then this method will read
  216.      * characters directly from the underlying stream into the given array.
  217.      * Thus redundant <code>BufferedReader</code>s will not copy data
  218.      * unnecessarily.
  219.      *
  220.      * @param      cbuf  Destination buffer
  221.      * @param      off   Offset at which to start storing characters
  222.      * @param      len   Maximum number of characters to read
  223.      *
  224.      * @return     The number of characters read, or -1 if the end of the
  225.      *             stream has been reached
  226.      *
  227.      * @exception  IOException  If an I/O error occurs
  228.      */
  229.     public int read(char cbuf[], int off, int len) throws IOException {
  230.         synchronized (lock) {
  231.         ensureOpen();
  232.             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  233.                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
  234.                 throw new IndexOutOfBoundsException();
  235.             } else if (len == 0) {
  236.                 return 0;
  237.             }
  238.  
  239.         int n = read1(cbuf, off, len);
  240.         if (n <= 0) return n;
  241.         while ((n < len) && in.ready()) {
  242.         int n1 = read1(cbuf, off + n, len - n);
  243.         if (n1 <= 0) break;
  244.         n += n1;
  245.         }
  246.         return n;
  247.     }
  248.     }
  249.  
  250.     /**
  251.      * Read a line of text.  A line is considered to be terminated by any one
  252.      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
  253.      * followed immediately by a linefeed.
  254.      *
  255.      * @param      skipLF  If true, the next '\n' will be skipped
  256.      *
  257.      * @return     A String containing the contents of the line, not including
  258.      *             any line-termination characters, or null if the end of the
  259.      *             stream has been reached
  260.      * 
  261.      * @see        java.io.LineNumberReader#readLine()
  262.      *
  263.      * @exception  IOException  If an I/O error occurs
  264.      */
  265.     String readLine(boolean skipLF) throws IOException {
  266.     StringBuffer s = new StringBuffer(defaultExpectedLineLength);
  267.     synchronized (lock) {
  268.         ensureOpen();
  269.  
  270.     bufferLoop:
  271.         for (;;) {
  272.  
  273.         if (nextChar >= nChars)
  274.             fill();
  275.         if (nextChar >= nChars) { /* EOF */
  276.             if (s.length() > 0)
  277.             return s.toString();
  278.             else
  279.             return null;
  280.         }
  281.         boolean eol = false;
  282.         char c = 0;
  283.         int i;
  284.  
  285.                 /* Skip a leftover '\n' */
  286.         if (skipLF && (cb[nextChar] == '\n'))
  287.                     nextChar++;
  288.  
  289.         charLoop:
  290.         for (i = nextChar; i < nChars; i++) {
  291.             c = cb[i];
  292.             if ((c == '\n') || (c == '\r')) {
  293.             eol = true;
  294.             break charLoop;
  295.             }
  296.         }
  297.         s.append(cb, nextChar, i - nextChar);
  298.         nextChar = i;
  299.  
  300.         if (eol) {
  301.             nextChar++;
  302.             if (c == '\r') {
  303.             if (nextChar >= nChars)
  304.                 fill();
  305.             if ((nextChar < nChars) && (cb[nextChar] == '\n'))
  306.                 nextChar++;
  307.             }
  308.             break bufferLoop;
  309.         }
  310.                 skipLF = false;
  311.             }
  312.     }
  313.  
  314.     return s.toString();
  315.     }
  316.  
  317.     /**
  318.      * Read a line of text.  A line is considered to be terminated by any one
  319.      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
  320.      * followed immediately by a linefeed.
  321.      *
  322.      * @return     A String containing the contents of the line, not including
  323.      *             any line-termination characters, or null if the end of the
  324.      *             stream has been reached
  325.      *
  326.      * @exception  IOException  If an I/O error occurs
  327.      */
  328.     public String readLine() throws IOException {
  329.         return readLine(false);
  330.     }
  331.  
  332.     /**
  333.      * Skip characters.
  334.      *
  335.      * @param  n  The number of characters to skip
  336.      *
  337.      * @return    The number of characters actually skipped
  338.      *
  339.      * @exception  IOException  If an I/O error occurs
  340.      */
  341.     public long skip(long n) throws IOException {
  342.     if (n < 0L) {
  343.         throw new IllegalArgumentException("skip value is negative");
  344.     }
  345.     synchronized (lock) {
  346.         ensureOpen();
  347.         long r = n;
  348.         while (r > 0) {
  349.         if (nextChar >= nChars)
  350.             fill();
  351.         if (nextChar >= nChars)    /* EOF */
  352.             break;
  353.         long d = nChars - nextChar;
  354.         if (r <= d) {
  355.             nextChar += r;
  356.             r = 0;
  357.             break;
  358.         }
  359.         else {
  360.             r -= d;
  361.             nextChar = nChars;
  362.         }
  363.         }
  364.         return n - r;
  365.     }
  366.     }
  367.  
  368.     /**
  369.      * Tell whether this stream is ready to be read.  A buffered character
  370.      * stream is ready if the buffer is not empty, or if the underlying
  371.      * character stream is ready.
  372.      *
  373.      * @exception  IOException  If an I/O error occurs
  374.      */
  375.     public boolean ready() throws IOException {
  376.     synchronized (lock) {
  377.         ensureOpen();
  378.         return (nextChar < nChars) || in.ready();
  379.     }
  380.     }
  381.  
  382.     /**
  383.      * Tell whether this stream supports the mark() operation, which it does.
  384.      */
  385.     public boolean markSupported() {
  386.     return true;
  387.     }
  388.  
  389.     /**
  390.      * Mark the present position in the stream.  Subsequent calls to reset()
  391.      * will attempt to reposition the stream to this point.
  392.      *
  393.      * @param readAheadLimit   Limit on the number of characters that may be
  394.      *                         read while still preserving the mark.  After
  395.      *                         reading this many characters, attempting to
  396.      *                         reset the stream may fail.  A limit value larger
  397.      *                         than the size of the input buffer will cause a
  398.      *                         new buffer to be allocated whose size is no
  399.      *                         smaller than limit.  Therefore large values
  400.      *                         should be used with care.
  401.      *
  402.      * @exception  IllegalArgumentException  If readAheadLimit is < 0
  403.      * @exception  IOException  If an I/O error occurs
  404.      */
  405.     public void mark(int readAheadLimit) throws IOException {
  406.     if (readAheadLimit < 0) {
  407.         throw new IllegalArgumentException("Read-ahead limit < 0");
  408.     }
  409.     synchronized (lock) {
  410.         ensureOpen();
  411.         this.readAheadLimit = readAheadLimit;
  412.         markedChar = nextChar;
  413.     }
  414.     }
  415.  
  416.     /**
  417.      * Reset the stream to the most recent mark.
  418.      *
  419.      * @exception  IOException  If the stream has never been marked,
  420.      *                          or if the mark has been invalidated
  421.      */
  422.     public void reset() throws IOException {
  423.     synchronized (lock) {
  424.         ensureOpen();
  425.         if (markedChar < 0)
  426.         throw new IOException((markedChar == INVALIDATED)
  427.                       ? "Mark invalid"
  428.                       : "Stream not marked");
  429.         nextChar = markedChar;
  430.     }
  431.     }
  432.  
  433.     /**
  434.      * Close the stream.
  435.      *
  436.      * @exception  IOException  If an I/O error occurs
  437.      */
  438.     public void close() throws IOException {
  439.     synchronized (lock) {
  440.         if (in == null)
  441.         return;
  442.         in.close();
  443.         in = null;
  444.         cb = null;
  445.     }
  446.     }
  447.  
  448. }
  449.